home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d939.lha / ExtraCmds / source_etc.lha / src / Compare.c < prev    next >
C/C++ Source or Header  |  1993-10-22  |  6KB  |  237 lines

  1. /*
  2.  *  COMPARE - Perform a byte-by-byte comparison of two files
  3.  *  Copyright (C) 1993 Torsten Poulin
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  The author can be contacted by s-mail at
  20.  *    Torsten Poulin
  21.  *    Banebrinken 99, 2, 77
  22.  *    DK-2400 Copenhagen NV
  23.  *    DENMARK
  24.  *
  25.  * $Id: Compare.c,v 37.5 93/06/21 08:33:41 Torsten Rel $
  26.  * $Log:    Compare.c,v $
  27.  * Revision 37.5  93/06/21  08:33:41  Torsten
  28.  * Now does its own buffering (32k per file) for increased throughput.
  29.  * 
  30.  * Revision 37.4  93/03/01  13:16:42  Torsten
  31.  * Fixed potentially dangerous bug: Input() could be closed.
  32.  * 
  33.  * Revision 37.3  93/02/17  09:24:59  Torsten
  34.  * Got rid of compiler warning caused by a forgotten '*' in
  35.  * the cast used in MyPrintf(). Otherwise nothing is changed ;-)
  36.  * 
  37.  * Revision 37.2  93/02/11  23:05:38  Torsten
  38.  * Removed unnecessary #include.
  39.  * Forgot to test the quiet flag before printing
  40.  * the 'initial subsequence' messages. Fixed that.
  41.  * 
  42.  * Revision 37.1  93/02/11  21:18:23  Torsten
  43.  * This is the initial version.
  44.  * 
  45.  */
  46.  
  47. #include <exec/types.h>
  48. #include <exec/memory.h>
  49. #include <dos/dos.h>
  50. #include <dos/dostags.h>
  51. #include <clib/macros.h>
  52. #include <clib/exec_protos.h>
  53. #include <clib/dos_protos.h>
  54. #ifdef __SASC
  55. #include <pragmas/exec_pragmas.h>
  56. #include <pragmas/dos_pragmas.h>
  57. #endif
  58. #include "tastlib.h"
  59. #include "compare_rev.h"
  60.  
  61. #define PROGNAME "Compare"
  62. #define TEMPLATE "FILE1,FILE2,SKIP1/N,SKIP2/N,QUIET/S"
  63. #define OPT_FILE1 0
  64. #define OPT_FILE2 1
  65. #define OPT_SKIP1 2
  66. #define OPT_SKIP2 3
  67. #define OPT_QUIET 4
  68. #define BUFLEN 32768L
  69.  
  70. char const versionID[] = VERSTAG;
  71. char const copyright[] = "$COPYRIGHT:Copyright © 1993 Torsten Poulin$";
  72.  
  73. typedef struct {
  74.   struct DosLibrary *DOSBase;
  75.   UBYTE buf1[BUFLEN];
  76.   UBYTE buf2[BUFLEN];
  77. } Global;
  78.  
  79. LONG Compare(BPTR, BPTR, BOOL, ULONG, ULONG, Global *);
  80.  
  81. LONG entrypoint(VOID) {
  82.   struct DosLibrary *DOSBase;
  83.   struct RDArgs *args;
  84.   Global *global;
  85.   LONG  arg[5];
  86.   LONG  rc = RETURN_OK;
  87.   BPTR  f1 = NULL, f2 = NULL;
  88.   UBYTE *name1, *name2;
  89.   ULONG skip1 = 0L, skip2 = 0L;
  90.  
  91.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
  92.     return RETURN_FAIL;
  93.  
  94.   if (!(global = AllocVec(sizeof(Global), MEMF_PUBLIC | MEMF_CLEAR)))
  95.     rc = ERROR_NO_FREE_STORE;
  96.   else {
  97.     global->DOSBase = DOSBase;
  98.  
  99.     arg[OPT_FILE1] = arg[OPT_FILE2] = 0L;
  100.     arg[OPT_SKIP1] = arg[OPT_SKIP2] = arg[OPT_QUIET] = 0L;
  101.     
  102.     if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
  103.       rc = RETURN_FAIL;
  104.     else {
  105.       name1 = (UBYTE *) arg[OPT_FILE1];
  106.       name2 = (UBYTE *) arg[OPT_FILE2];
  107.         
  108.       if (!arg[OPT_FILE1])
  109.     f1 = Input();
  110.       else if (!(f1 = Open(name1, MODE_OLDFILE)))
  111.     rc = RETURN_ERROR;
  112.         
  113.       if (!arg[OPT_FILE2]) {
  114.     if (arg[OPT_FILE1])
  115.       f2 = Input();
  116.     else {
  117.       /* Maybe I should print something more informative... */
  118.       SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  119.       rc = RETURN_FAIL;
  120.     }
  121.       }
  122.       else if (!(f2 = Open(name2, MODE_OLDFILE))) {
  123.     if (arg[OPT_FILE1])
  124.       Close(f1);
  125.     rc = RETURN_ERROR;
  126.       }
  127.  
  128.       if (arg[OPT_SKIP1])
  129.     skip1 = *(LONG *) arg[OPT_SKIP1];
  130.  
  131.       if (arg[OPT_SKIP2])
  132.     skip2 = *(LONG *) arg[OPT_SKIP2];
  133.  
  134.       if (f1 && f2) {
  135.     rc = Compare(f1, f2, (BOOL) arg[OPT_QUIET], skip1, skip2, global);
  136.     if (arg[OPT_FILE1])
  137.       Close(f1);
  138.     if (arg[OPT_FILE2])
  139.       Close(f2);
  140.       }
  141.       FreeArgs(args);
  142.     }
  143.     FreeVec(global);
  144.   }
  145.   rc = printErrorMsg(rc, PROGNAME, DOSBase);
  146.   CloseLibrary((struct Library *) DOSBase);
  147.   return rc;
  148. }
  149.  
  150.  
  151. LONG Compare(BPTR f1, BPTR f2, BOOL quiet, ULONG skip1, ULONG skip2,
  152.          Global *global)
  153. {
  154.   struct DosLibrary *DOSBase = global->DOSBase;
  155.   UBYTE *bufp1, *bufend1, *bufp2, *bufend2;
  156.   LONG  rlen1 = 0L, rlen2 = 0L;
  157.   LONG c1, c2;
  158.   ULONG lines = 1L, offset = 0L;
  159.  
  160.   bufp1 = bufend1 = global->buf1;
  161.   bufp2 = bufend2 = global->buf2;
  162.  
  163.   while (skip1 -= rlen1) {
  164.     if ((rlen1 = Read(f1, bufp1, MIN(skip1, BUFLEN))) <= 0) {
  165.       if (rlen1 == 0)
  166.     PutStr("Offset beyond end of FILE1\n");
  167.       return RETURN_ERROR;
  168.     }
  169.     if (CheckSignal(SIGBREAKF_CTRL_C))
  170.       return ERROR_BREAK;
  171.   }
  172.  
  173.   while (skip2 -= rlen2) {
  174.     if ((rlen2 = Read(f2, bufp2, MIN(skip2, BUFLEN))) <= 0) {
  175.       if (rlen2 == 0)
  176.     PutStr("Offset beyond end of FILE2\n");
  177.       return RETURN_ERROR;
  178.     }
  179.     if (CheckSignal(SIGBREAKF_CTRL_C))
  180.       return ERROR_BREAK;
  181.   }
  182.  
  183.   for(;;) {
  184.     if (bufp1 >= bufend1) {
  185.       bufp1 = global->buf1;
  186.       if ((rlen1 = Read(f1, bufp1, BUFLEN)) > 0)
  187.     bufend1 = global->buf1 + rlen1;
  188.       if (CheckSignal(SIGBREAKF_CTRL_C))
  189.     return ERROR_BREAK;
  190.     }
  191.     c1 = *bufp1++;
  192.  
  193.     if (bufp2 >= bufend2) {
  194.       bufp2 = global->buf2;
  195.       if ((rlen2 = Read(f2, bufp2, BUFLEN)) > 0)
  196.     bufend2 = global->buf2 + rlen2;
  197.       if (CheckSignal(SIGBREAKF_CTRL_C))
  198.     return ERROR_BREAK;
  199.     }
  200.     c2 = *bufp2++;
  201.  
  202.     if (rlen1 <= 0 || rlen2 <= 0)
  203.       break;            /* error or EOF */
  204.  
  205.     offset++;
  206.  
  207.     if (c1 != c2) {
  208.       if (!quiet) {
  209.     MyPrintf(global,
  210.          "Files differ at offset %lu (hex 0x%lx), line %ld\n",
  211.          offset, offset, lines);
  212.       }
  213.       SetIoErr(0L);
  214.       return RETURN_WARN;
  215.     }
  216.  
  217.     if (c1 == '\n')
  218.       lines++;
  219.   }
  220.  
  221.   if (rlen1 < 0 || rlen2 < 0)
  222.     return RETURN_ERROR;    /* An error occured while reading */
  223.  
  224.   if (rlen1 == 0 && rlen2 != 0) {
  225.     if (!quiet)
  226.       PutStr("FILE1 is an initial subsequence of FILE2\n");
  227.     return RETURN_WARN;
  228.   }
  229.  
  230.   if (rlen1 != 0 && rlen2 == 0) {
  231.     if (!quiet)
  232.       PutStr("FILE2 is an initial subsequence of FILE1\n");
  233.     return RETURN_WARN;
  234.   }
  235.   return RETURN_OK;
  236. }
  237.